//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V1.0.0
/********************************************************
    说明：
    1、这个基于FSMC模拟LCD8080时序。
    2、目前只支持8位、16位并行通信。
    3、基于stm32f4xx标准库V1.9.0
**********************************************************/
#ifndef __FSMC8080_BSP_H__
#define __FSMC8080_BSP_H__

/*****************************************************/
#include "stm32f4xx.h"
#include "stm32f4xx_fsmc.h"
#include "stm32f4xx_fmc.h"
#include "../GPIO_BSP/gpio_bsp.h"
/*****************************************************/


//LCD8080数据线是多少位
#define FSMC8080_Data_Width_bit   16

/*
每个 BANK存储区域 有4 * 64MB = 256MB
64MB : FSMC_Bank1_NORSRAM1:  0X6000 0000 ~0X63FF FFFF
64MB : FSMC_Bank1_NORSRAM2 : 0X6400 0000 ~0X67FF FFFF
64MB : FSMC_Bank1_NORSRAM3 : 0X6800 0000 ~0X6BFF FFFF
64MB : FSMC_Bank1_NORSRAM4 : 0X6C00 0000 ~0X6FFF FFFF

FSMC_A16引脚  接LCD的DC(寄存器 / 数据选择)脚
选择BANK1 - FSMC_Bank1_NORSRAM1
LCD写命令 = 0x60000000
LCD写数据 = 0x60020000 = 0x60000000 + (1<<16+1) = 0x60000000 + 0x20000 = 0x60020000
LCD读数据 = 0x60020000 = 0x60000000 + (1<<16+1) = 0x60000000 + 0x20000 = 0x60020000

选择BANK1 - FSMC_Bank1_NORSRAM2
LCD写命令 = 0x64000000
LCD写数据 = 0x64020000 = 0x64000000 + (1<<16+1) = 0x64000000 + 0x20000 = 0x64020000
LCD读数据 = 0x64020000 = 0x64000000 + (1<<16+1) = 0x64000000 + 0x20000 = 0x64020000

选择BANK1 - FSMC_Bank1_NORSRAM3
LCD写命令 = 0x68000000
LCD写数据 = 0x68020000 = 0x68000000 + (1<<16+1) = 0x68000000 + 0x20000 = 0x68020000
LCD读数据 = 0x68020000 = 0x68000000 + (1<<16+1) = 0x68000000 + 0x20000 = 0x68020000

选择BANK1 - FSMC_Bank1_NORSRAM4
LCD写命令 = 0x6C000000
LCD写数据 = 0x6C020000 = 0x6C000000 + (1<<16+1) = 0x6C000000 + 0x20000 = 0x6C020000
LCD读数据 = 0x6C020000 = 0x6C000000 + (1<<16+1) = 0x6C000000 + 0x20000 = 0x6C020000
*/


//FSMC_Bank1_NORSRAM1用于LCD命令操作的地址
#define  FSMC8080_Write_CMD       ((unsigned int)0x60000000)
//FSMC_Bank1_NORSRAM1用于LCD数据操作的地址
#define  FSMC8080_Write_DATA  	  ((unsigned int)0x60020000)
#define  FSMC8080_Read_DATA       FSMC8080_Write_DATA

/************************************控制信号线*********************************/
//片选，选择NOR_SRAM块 
//FSMC_Bank1_NORSRAM1的默认片选引脚PD7
//FSMC_Bank1_NORSRAM2的默认片选引脚PG9
//FSMC_Bank1_NORSRAM3的默认片选引脚PG10
//FSMC_Bank1_NORSRAM4的默认片选引脚PG12
#define  LCD_CS_PORT         PortD
#define  LCD_CS_PIN          Pin7

//DC引脚，使用FSMC的地址信号控制，本引脚决定了访问LCD时使用的地址
//PD11为FSMC_A16
//PD12为FSMC_A17 FSMC不用的话不能配置复用模式
//PD13为FSMC_A18 FSMC不用的话不能配置复用模式
//其它FSMC的地址引脚就不列举了
#define  LCD_DC_PORT         PortD
#define  LCD_DC_PIN          Pin11

//写使能   
#define  LCD_WR_PORT         PortD
#define  LCD_WR_PIN          Pin5

//读使能   
#define  LCD_RD_PORT         PortD
#define  LCD_RD_PIN          Pin4

/********************************FSMC数据信号线*************************************/ 
    #define  FSMC_D0_PORT        PortD
    #define  FSMC_D0_PIN         Pin14

    #define  FSMC_D1_PORT        PortD
    #define  FSMC_D1_PIN         Pin15

    #define  FSMC_D2_PORT        PortD
    #define  FSMC_D2_PIN         Pin0

    #define  FSMC_D3_PORT        PortD
    #define  FSMC_D3_PIN         Pin1

    #define  FSMC_D4_PORT        PortE
    #define  FSMC_D4_PIN         Pin7

    #define  FSMC_D5_PORT        PortE
    #define  FSMC_D5_PIN         Pin8

    #define  FSMC_D6_PORT        PortE
    #define  FSMC_D6_PIN         Pin9

    #define  FSMC_D7_PORT        PortE
    #define  FSMC_D7_PIN         Pin10
#if (FSMC8080_Data_Width_bit >= 16)
    #define  FSMC_D8_PORT        PortE
    #define  FSMC_D8_PIN         Pin11

    #define  FSMC_D9_PORT        PortE
    #define  FSMC_D9_PIN         Pin12

    #define  FSMC_D10_PORT       PortE
    #define  FSMC_D10_PIN        Pin13

    #define  FSMC_D11_PORT       PortE
    #define  FSMC_D11_PIN        Pin14

    #define  FSMC_D12_PORT       PortE
    #define  FSMC_D12_PIN        Pin15

    #define  FSMC_D13_PORT       PortD
    #define  FSMC_D13_PIN        Pin8

    #define  FSMC_D14_PORT       PortD
    #define  FSMC_D14_PIN        Pin9  

    #define  FSMC_D15_PORT       PortD
    #define  FSMC_D15_PIN        Pin10
#endif
#if (FSMC8080_Data_Width_bit >= 32)
    #define  FSMC_D16_PORT       PortH
    #define  FSMC_D16_PIN        Pin8

    #define  FSMC_D17_PORT       PortH
    #define  FSMC_D17_PIN        Pin9

    #define  FSMC_D18_PORT       PortH
    #define  FSMC_D18_PIN        Pin10

    #define  FSMC_D19_PORT       PortH
    #define  FSMC_D19_PIN        Pin11

    #define  FSMC_D20_PORT       PortH
    #define  FSMC_D20_PIN        Pin12

    #define  FSMC_D21_PORT       PortH
    #define  FSMC_D21_PIN        Pin13

    #define  FSMC_D22_PORT       PortH
    #define  FSMC_D22_PIN        Pin14

    #define  FSMC_D23_PORT       PortH
    #define  FSMC_D23_PIN        Pin15

    #define  FSMC_D24_PORT       PortI
    #define  FSMC_D24_PIN        Pin0

    #define  FSMC_D25_PORT       PortI
    #define  FSMC_D25_PIN        Pin1

    #define  FSMC_D26_PORT       PortI
    #define  FSMC_D26_PIN        Pin2

    #define  FSMC_D27_PORT       PortI
    #define  FSMC_D27_PIN        Pin3

    #define  FSMC_D28_PORT       PortI
    #define  FSMC_D28_PIN        Pin6

    #define  FSMC_D29_PORT       PortI
    #define  FSMC_D29_PIN        Pin7

    #define  FSMC_D30_PORT       PortI
    #define  FSMC_D30_PIN        Pin9

    #define  FSMC_D31_PORT       PortI
    #define  FSMC_D31_PIN        Pin10
#endif

/*FSMC8080状态枚举*/
typedef enum
{
    FSMC8080_TRx_Idle  = 0,//空闲
    FSMC8080_TRx_Busy  = 1,//忙碌
}WHT_FSMC8080_State_enum;

/*FSMC8080信息结构体*/
typedef struct
{
    unsigned char Mount_Count;        //设备个数
    FlagStatus BSP_Mutex;             //驱动锁
    WHT_FSMC8080_State_enum TRx_State;//忙碌标志,自动清零
}WHT_FSMC8080_Info_t;

/*FSMC8080回调函数结构体*/
typedef struct
{
    volatile WHT_FSMC8080_Info_t* WHT_Info;
    ErrorStatus(*WHT_Set_BSP_Mutex)(void);                                     //驱动外设上锁,返回SUCCESS或ERROR
    void (*WHT_Clr_BSP_Mutex)(void);                                           //驱动外设解锁
#if (FSMC8080_Data_Width_bit == 8)
    void (*WHT_Write_Cmd)(unsigned char cmd);                                   //向LCD写命令
    void (*WHT_Write_Data)(const unsigned char* input_buf, unsigned int count); //向LCD写数据
    void (*WHT_Write)(unsigned char cmd, const unsigned char* input_buf, unsigned int count);  //向LCD指定地址写数据
    void (*WHT_Read)(unsigned char cmd, unsigned char* output_buf, unsigned int count);        //向LCD指定地址读数据
#elif (FSMC8080_Data_Width_bit == 16)
    void (*WHT_Write_Cmd)(unsigned short cmd);                                   //向LCD写命令
    void (*WHT_Write_Data)(const unsigned short* input_buf, unsigned int count); //向LCD写数据
    void (*WHT_Write)(unsigned short cmd, const unsigned short* input_buf, unsigned int count);  //向LCD指定地址写数据
    void (*WHT_Read)(unsigned short cmd, unsigned short* output_buf, unsigned int count);        //向LCD指定地址读数据
#elif (FSMC8080_Data_Width_bit == 32)
    void (*WHT_Write_Cmd)(unsigned int cmd);                                   //向LCD写命令
    void (*WHT_Write_Data)(const unsigned int* input_buf, unsigned int count); //向LCD写数据
    void (*WHT_Write)(unsigned int cmd, const unsigned int* input_buf, unsigned int count);  //向LCD指定地址写数据
    void (*WHT_Read)(unsigned int cmd, unsigned int* output_buf, unsigned int count);        //向LCD指定地址读数据
#endif
}WHT_FSMC8080_BSP_t;

/*FSMC8080注册API*/
extern void WHT_FSMC8080_BSP_Register(WHT_FSMC8080_BSP_t* bsp);

#endif // !__FSMC8080_BSP_H__
